package org.egrit;

import java.awt.Point;

import com.google.common.base.Predicate;
import com.vividsolutions.jts.geom.Polygon;

/**
 * Defines a writable grid.
 * 
 * @author michael
 */
public interface IWritableGrid extends IGrid {
    
    /**
     * Sets the value of the given grid cell. The value will be coerced to
     * the data type of the grid if necessary.
     * 
     * @param gridX grid X ordinate
     * @param gridY grid Y ordinate
     * @param value the value to set
     * 
     * @return {@code true} if the value was set; {@code false} if the location
     *     was beyond the bounds of the grid
     */
    boolean setGridValue(int gridX, int gridY, Number value);
    
    /**
     * Sets the value of the given grid cell. The value will be coerced to
     * the data type of the grid if necessary.
     * 
     * @param gridPos grid position
     * @param value the value to set
     * 
     * @return {@code true} if the value was set; {@code false} if the location
     *     was beyond the bounds of the grid
     */
    boolean setGridValue(Point gridPos, Number value);
    
    /**
     * Sets the value of the given grid cell subject to the cell's current value
     * satisfying the given condition. The value will be coerced to
     * the data type of the grid if necessary.
     * 
     * @param gridX grid X ordinate
     * @param gridY grid Y ordinate
     * @param value the value to set
     * @param cond the condition which must be satisfied by the cell's current value
     * 
     * @return {@code true} if the value was set; {@code false} if the condition is
     *     not satisfied or if the location was beyond the bounds of the grid
     */
    boolean setGridValue(int gridX, int gridY, Number value, Predicate<Number> cond);
    
    /**
     * Sets the value of all grid cells within the given bounds.
     * Any portions of the bounds beyond the grid bounds are ignored.
     * 
     * @param bounds bounds within which to set cell values
     * @param value the value to set
     * 
     * @return the number of cells set
     */
    int setGridValue(IGridBounds bounds, Number value);
    
    /**
     * Sets the value of all grid cells within the given bounds
     * and whose current values satisfy the given condition.
     * Any portions of the bounds beyond the grid bounds are ignored.
     * 
     * @param bounds bounds within which to set cell values
     * @param value the value to set
     * @param cond the condition which must be satisfied by a cell's current value
     * 
     * @return the number of cells set
     */
    int setGridValue(IGridBounds bounds, Number value, Predicate<Number> cond);
    
    /**
     * Sets the value of all grid cells whose centres lie within the given polygon.
     * Any portions of the polygon beyond the grid bounds are ignored.
     * 
     * @param poly the polygon covering cells to set
     * @param value the value to set
     * 
     * @return the number of cells set
     */
    int setGridValue(Polygon poly, Number value);
    
    /**
     * Sets the value of all grid cells whose centres lie within the given polygon
     * and whose current values satisfy the given condition.
     * Any portions of the polygon beyond the grid bounds are ignored.
     * 
     * @param poly the polygon covering cells to set
     * @param value the value to set
     * @param cond the condition which must be satisfied by a cell's current value
     * 
     * @return the number of cells set
     */
    int setGridValue(Polygon poly, Number value, Predicate<Number> cond);

    /**
     * Gets a region of this grid as a new writable grid. The region may extend
     * beyond the bounds of this grid, in which case cells will have this grid's
     * outside value.
     * 
     * @param regionBounds bounds of the region to extract
     * 
     * @return a new writable grid based on the region in this grid
     */
    IWritableGrid getWritableRegion(IGridBounds regionBounds);
}
